package wiiusej.apptest.activityTasks;

import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.Priority;
import org.apache.log4j.PropertyConfigurator;

import wiiusej.Wiimote;
import wiiusej.apptest.WiimoteEventListener;
import wiiusej.apptest.statistics.AccelerationPaquet;

public class RealTimeFeedback extends Thread{

	private Vector<AccelerationPaquet> myEventVector;
	
	//Logger
	private static Logger fileLogger;
	private static Logger fileLoggerDelay;
	
	private static final String fileURL = "src/test/java/wiiusej/apptest/statistics/logs/RealTimeFeedback";
	private static final String fileURLDelay = "src/test/java/wiiusej/apptest/statistics/delay/logs/Acc_to_RT";
	
	//Speaker Parameters
	private static final int THIRD_LEVEL_FREQ = 1000;
	private static final int FIFTH_LEVEL_FREQ = 250;
		
	//RealTime APP modes
	private final int MODE_SLOWMOTION = 0;
	private final int MODE_BIGSOFTMOTION = 1;
	private final int MODE_ROBOTIC = 2;
	private final int MODE_REST = 3;
	
	//COM queues
	private BlockingQueue<Vector<AccelerationPaquet>> comQueue;
	private BlockingQueue<Integer> toGameQ;
	//private BlockingQueue<Integer> toRumbleQ = new LinkedBlockingQueue<Integer>();
	private BlockingQueue<Integer> toSoundQ = new LinkedBlockingQueue<Integer>();
	
	
	private long lastSize = 0;
	
	public RealTimeFeedback(BlockingQueue comQueue, BlockingQueue toGameController, 
			BlockingQueue<Integer> toSoundQ){
		
		this.toGameQ = toGameController;
		this.comQueue = comQueue;
				
		//this.toRumbleQ = toRumbleQ2;
		this.toSoundQ = toSoundQ;
		
		PropertyConfigurator.configure("log4j.properties");
		fileLogger = Logger.getLogger("realTimeFeedback");
		fileLoggerDelay = Logger.getLogger("delayAccToRT");				
	}	
	
	
	
	@Override
	public void run(){
	
		SimpleDateFormat tsFormat = new SimpleDateFormat("mm:ss:SS");
		
		while(true){
			
			try {
				myEventVector = comQueue.take();				
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			if(myEventVector.size() > lastSize){
			
				fileLogger.info("MyEventVector Size: " + myEventVector.size() + 
						" Lastsize: " + lastSize );
				
				Timestamp now = new Timestamp(System.currentTimeMillis());
				long accPacketDelay = now.getTime() - myEventVector.lastElement().getTime().getTime();				
				
				fileLoggerDelay.info(accPacketDelay);				
				fileLogger.info("Analyzing LastElement - Time: " + 
						tsFormat.format(myEventVector.lastElement().getTime()) 
						+ " PacketsinPeriod: " + myEventVector.lastElement().getCounter());
				
				
				calculeLastPaquetMean(myEventVector.lastElement(), tsFormat);				
				lastSize = myEventVector.size();				
				fileLogger.info("");				
			}			
		}		
	}

	
	private void calculeLastPaquetMean(AccelerationPaquet nextToLastChecked, SimpleDateFormat tsFormat) {
		
		int meanX, meanY, meanZ;
			
		if( nextToLastChecked != null){
			
			meanX = meanAxis((Vector<Integer>) nextToLastChecked.getAccX().clone());
			meanY = meanAxis((Vector<Integer>)nextToLastChecked.getAccY().clone());
			meanZ = meanAxis((Vector<Integer>)nextToLastChecked.getAccZ().clone());
			
			giveFeedback(meanX, meanY, meanZ, tsFormat, nextToLastChecked);
				
		}		
	}

	private int meanAxis(Vector<Integer> axisVector){
						
			int mean = 0; 
			for(Integer i : axisVector){
				
				if(i<= 85){
					i = 255 - i;
				}
				
				mean = mean + i;
			}
			
			return mean/axisVector.size();	
		
	}
	
	private void printReport(int meanX, int meanY, int meanZ, SimpleDateFormat tsFormat, String motion,
			AccelerationPaquet toCheck){
		
		fileLogger.debug(" ");
		fileLogger.debug("Paquet: " + tsFormat.format(toCheck.getTime())
				+ " MeanX: " + meanX
				+ " MeanY: " + meanY
				+ " MeanZ: " + meanZ + motion);		
		
		
	}
	
	private void giveFeedback(int meanX, int meanY, int meanZ, SimpleDateFormat tsFormat, 
			AccelerationPaquet toCheck){
		
		if(meanZ >= 160 || meanX >= 160 || meanY >= 160){
			//BigSoftMotion
			//fileLogger.info("MeanZ : " + meanZ + " BIG SOFT MOTION");
			
			try {
				toGameQ.put(MODE_BIGSOFTMOTION);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			printReport(meanX, meanY, meanZ, tsFormat, " BIG SOFT MOTION", toCheck);	
			//soundCell.setFrequencyMillis(FIFTH_LEVEL_FREQ);
			//SlowMotionDetector
			fileLogger.info(" BIG SOFT MOTION at: " + tsFormat.format(System.currentTimeMillis()));
			//toRumbleQ.add(1);		
			toSoundQ.add(FIFTH_LEVEL_FREQ);
			
						
		}else if(detectPeaks(toCheck)){
			
				try {
					toGameQ.put(MODE_ROBOTIC);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}				
				
				fileLogger.info(" ROBOTIC MOTION at: " + tsFormat.format(System.currentTimeMillis()));
				//toRumbleQ.add(0);
				toSoundQ.add(THIRD_LEVEL_FREQ);
				//Normal Motion
				//fileLogger.info("MeanZ : " + meanZ + " NORMAL MOTION");
				printReport(meanX, meanY, meanZ, tsFormat, " NORMAL MOTION", toCheck);	
				//soundCell.setFrequencyMillis(THIRD_LEVEL_FREQ);				
				
		}else{
			
				if(!detectRestPosition(meanX, meanY, meanZ)){
					fileLogger.info(" SLOW MOTION at: " + tsFormat.format(System.currentTimeMillis()));
					try {
						toGameQ.put(MODE_SLOWMOTION);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}					
					
					
					//toRumbleQ.add(0);
					//fileLogger.info("MeanZ : " + meanZ + " LOW MOTION");
					printReport(meanX, meanY, meanZ, tsFormat, " LOW MOTION", toCheck);
					//soundCell.setFrequencyMillis(FIRST_LEVEL_FREQ);
					
				}else{
					fileLogger.info(" RESt POSITION  at: " + tsFormat.format(System.currentTimeMillis()));
					try {
						toGameQ.put(MODE_REST);
						//toRumbleQ.add(1);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
				}
								
			}		
		}		
	
	private boolean detectRestPosition(int meanX, int meanY, int meanZ){
		
		
		if(meanX > 140 || meanY > 140 || meanZ > 140){			
			return false;
		}
		
		if(  (meanX > 120 && meanX < 130) || (meanY > 120 && meanY < 130)){
			return true;			
		}
		
		if((meanX > 120 && meanX < 130) || (meanZ > 120 && meanZ < 130)){
			return true;			
		}
		
		if((meanY > 120 && meanY < 130) || (meanZ > 120 && meanZ < 130)){
			return true;			
		}
		
		
		
		return false;
	}
	
		
	private boolean detectPeaks(AccelerationPaquet toCheck){
		
		boolean peak = false;
		
		for(Integer i : toCheck.getAccX()){
			if(i > 190 || i < 70){
				peak = true;
			}			
		}
		
		for(Integer i : toCheck.getAccY()){
			if(i > 190 || i < 70){
				peak = true;
			}			
		}
		
		for(Integer i : toCheck.getAccZ()){
			if(i > 190 || i < 70){
				peak = true;
			}			
		}
		
		return peak;
	}
	
	
	


	
	
	
	




	
	
	
	
	
}
